<template>
  <div class="camera-scanner">
    <div class="camera-container">
      <video 
        ref="videoRef" 
        :class="{ active: isScanning }"
        autoplay 
        playsinline
        muted
      ></video>
      <canvas ref="canvasRef" style="display: none;"></canvas>
      
      <!-- 扫描框 -->
      <div class="scan-frame" v-if="isScanning">
        <div class="scan-line"></div>
        <div class="corner top-left"></div>
        <div class="corner top-right"></div>
        <div class="corner bottom-left"></div>
        <div class="corner bottom-right"></div>
      </div>
      
      <!-- 权限提示 -->
      <div v-if="permissionDenied" class="permission-denied">
        <div class="permission-icon">
          <ExclamationCircleOutlined />
        </div>
        <h3>摄像头权限被拒绝</h3>
        <p>请在浏览器设置中允许访问摄像头，然后刷新页面重试</p>
        <a-button @click="requestPermission" type="primary">
          重新请求权限
        </a-button>
      </div>
      
      <!-- 不支持提示 -->
      <div v-if="notSupported" class="not-supported">
        <div class="not-supported-icon">
          <StopOutlined />
        </div>
        <h3>不支持摄像头功能</h3>
        <p>您的浏览器不支持摄像头功能，请使用图片上传方式</p>
      </div>
    </div>
    
    <div class="camera-controls">
      <a-button 
        v-if="!isScanning && !permissionDenied && !notSupported" 
        @click="startScanning" 
        type="primary" 
        size="large"
        :loading="isStarting"
      >
        <template #icon>
          <CameraOutlined />
        </template>
        {{ isStarting ? '启动中...' : '开始扫描' }}
      </a-button>
      
      <div v-else-if="isScanning" class="scanning-controls">
        <a-button @click="stopScanning" size="large">
          <template #icon>
            <StopOutlined />
          </template>
          停止扫描
        </a-button>
        <a-button @click="captureImage" type="primary" size="large">
          <template #icon>
            <CameraOutlined />
          </template>
          拍照识别
        </a-button>
        <a-button @click="switchCamera" size="large" v-if="hasMultipleCameras">
          <template #icon>
            <RetweetOutlined />
          </template>
          切换摄像头
        </a-button>
      </div>
    </div>
    
    <!-- 扫描状态 -->
    <div v-if="isScanning" class="scan-status">
      <div class="status-item">
        <span class="status-label">扫描状态:</span>
        <span class="status-value scanning">正在扫描...</span>
      </div>
      <div class="status-item">
        <span class="status-label">扫描次数:</span>
        <span class="status-value">{{ scanCount }}</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
import { message } from 'ant-design-vue'
import {
  CameraOutlined,
  StopOutlined,
  RetweetOutlined,
  ExclamationCircleOutlined
} from '@ant-design/icons-vue'
import { decodeFromVideo, DecodeResult } from '../utils/qrDecoder'

// 定义事件
const emit = defineEmits<{
  'decode-success': [result: DecodeResult]
  'decode-error': [error: string]
}>()

// 响应式数据
const videoRef = ref<HTMLVideoElement>()
const canvasRef = ref<HTMLCanvasElement>()
const isScanning = ref(false)
const isStarting = ref(false)
const permissionDenied = ref(false)
const notSupported = ref(false)
const hasMultipleCameras = ref(false)
const currentFacingMode = ref<'user' | 'environment'>('environment')
const scanCount = ref(0)
const stream = ref<MediaStream | null>(null)
const scanInterval = ref<number | null>(null)

// 组件挂载时检查浏览器支持
onMounted(() => {
  checkBrowserSupport()
})

// 组件卸载时清理资源
onUnmounted(() => {
  stopScanning()
})

// 检查浏览器支持
const checkBrowserSupport = () => {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    notSupported.value = true
    return
  }
  
  // 检查是否有多个摄像头
  navigator.mediaDevices.enumerateDevices().then(devices => {
    const videoDevices = devices.filter(device => device.kind === 'videoinput')
    hasMultipleCameras.value = videoDevices.length > 1
  }).catch(error => {
    console.warn('无法枚举设备:', error)
  })
}

// 请求摄像头权限
const requestPermission = async () => {
  try {
    const testStream = await navigator.mediaDevices.getUserMedia({ video: true })
    testStream.getTracks().forEach(track => track.stop())
    permissionDenied.value = false
  } catch (error) {
    console.error('权限请求失败:', error)
    permissionDenied.value = true
  }
}

// 开始扫描
const startScanning = async () => {
  if (notSupported.value) {
    message.error('您的浏览器不支持摄像头功能')
    return
  }
  
  isStarting.value = true
  
  try {
    const constraints = {
      video: {
        facingMode: currentFacingMode.value,
        width: { ideal: 1280 },
        height: { ideal: 720 }
      }
    }
    
    stream.value = await navigator.mediaDevices.getUserMedia(constraints)
    
    if (videoRef.value) {
      videoRef.value.srcObject = stream.value
      await videoRef.value.play()
      
      isScanning.value = true
      permissionDenied.value = false
      scanCount.value = 0
      
      // 开始定时扫描
      startScanLoop()
      
      message.success('摄像头启动成功，开始扫描')
    }
  } catch (error) {
    console.error('摄像头启动失败:', error)
    
    if (error instanceof Error) {
      if (error.name === 'NotAllowedError') {
        permissionDenied.value = true
        message.error('摄像头权限被拒绝')
      } else if (error.name === 'NotFoundError') {
        message.error('未找到摄像头设备')
      } else {
        message.error('摄像头启动失败: ' + error.message)
      }
    } else {
      message.error('摄像头启动失败')
    }
  } finally {
    isStarting.value = false
  }
}

// 停止扫描
const stopScanning = () => {
  if (scanInterval.value) {
    clearInterval(scanInterval.value)
    scanInterval.value = null
  }
  
  if (stream.value) {
    stream.value.getTracks().forEach(track => track.stop())
    stream.value = null
  }
  
  if (videoRef.value) {
    videoRef.value.srcObject = null
  }
  
  isScanning.value = false
  scanCount.value = 0
}

// 开始扫描循环
const startScanLoop = () => {
  scanInterval.value = setInterval(() => {
    scanVideoFrame()
  }, 100) // 每100ms扫描一次
}

// 扫描视频帧
const scanVideoFrame = () => {
  if (!videoRef.value || !isScanning.value) return
  
  scanCount.value++
  
  try {
    const result = decodeFromVideo(videoRef.value)
    if (result) {
      stopScanning()
      emit('decode-success', result)
      message.success('二维码识别成功！')
    }
  } catch (error) {
    console.error('扫描帧失败:', error)
  }
}

// 拍照识别
const captureImage = () => {
  if (!videoRef.value || !canvasRef.value) return
  
  const canvas = canvasRef.value
  const video = videoRef.value
  const ctx = canvas.getContext('2d')
  
  if (!ctx) return
  
  canvas.width = video.videoWidth
  canvas.height = video.videoHeight
  ctx.drawImage(video, 0, 0)
  
  try {
    const result = decodeFromVideo(video)
    if (result) {
      stopScanning()
      emit('decode-success', result)
      message.success('二维码识别成功！')
    } else {
      message.warning('未识别到二维码，请调整角度或距离后重试')
    }
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : '识别失败'
    emit('decode-error', errorMessage)
  }
}

// 切换摄像头
const switchCamera = async () => {
  currentFacingMode.value = currentFacingMode.value === 'user' ? 'environment' : 'user'
  
  if (isScanning.value) {
    stopScanning()
    await startScanning()
  }
}
</script>

<style scoped>
.camera-scanner {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.camera-container {
  position: relative;
  flex: 1;
  min-height: 300px;
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 8px;
}

video.active {
  display: block;
}

.scan-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 200px;
  height: 200px;
  border: 2px solid rgba(255, 255, 255, 0.5);
  border-radius: 8px;
}

.scan-line {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, #00ff00, transparent);
  animation: scan 2s linear infinite;
}

@keyframes scan {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(196px);
  }
}

.corner {
  position: absolute;
  width: 20px;
  height: 20px;
  border: 3px solid #00ff00;
}

.corner.top-left {
  top: -3px;
  left: -3px;
  border-right: none;
  border-bottom: none;
}

.corner.top-right {
  top: -3px;
  right: -3px;
  border-left: none;
  border-bottom: none;
}

.corner.bottom-left {
  bottom: -3px;
  left: -3px;
  border-right: none;
  border-top: none;
}

.corner.bottom-right {
  bottom: -3px;
  right: -3px;
  border-left: none;
  border-top: none;
}

.permission-denied,
.not-supported {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: white;
  padding: 40px 20px;
  gap: 16px;
}

.permission-icon,
.not-supported-icon {
  font-size: 48px;
  color: #ff4d4f;
}

.permission-denied h3,
.not-supported h3 {
  margin: 0;
  font-size: 18px;
  font-weight: 600;
}

.permission-denied p,
.not-supported p {
  margin: 0;
  font-size: 14px;
  opacity: 0.8;
  line-height: 1.5;
}

.camera-controls {
  display: flex;
  justify-content: center;
  gap: 12px;
}

.scanning-controls {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: center;
}

.scan-status {
  background: rgba(255, 255, 255, 0.9);
  border-radius: 8px;
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 14px;
}

.status-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.status-label {
  color: #666;
  font-weight: 500;
}

.status-value {
  color: #1a1a1a;
  font-weight: 600;
}

.status-value.scanning {
  color: #52c41a;
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.5;
  }
}

/* 响应式设计 */
@media (max-width: 768px) {
  .camera-container {
    min-height: 250px;
  }
  
  .scan-frame {
    width: 150px;
    height: 150px;
  }
  
  .scanning-controls {
    flex-direction: column;
    width: 100%;
  }
  
  .scanning-controls .ant-btn {
    width: 100%;
  }
  
  .scan-status {
    flex-direction: column;
    gap: 8px;
    text-align: center;
  }
}
</style>